package com.ecp.commons.serialization;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONException;
import org.json.JSONObject;

import com.ecp.commons.Global;
import com.ecp.commons.annotation.VariantType;
import com.ecp.commons.session.SessionSerializable;

public class GenericBean implements SerializableObject, SessionSerializable {
	protected Map<String, Variant>	map		= new LinkedHashMap<String, Variant>();
	protected String				entity	= "";

	private static final Log		log		= LogFactory.getLog(GenericBean.class);

	public GenericBean() {
		defineVariantSet();
		resetValues();
	}

	@Override
	public void defineVariantSet() {

	}

	@Override
	public void resetValues() {

	}

	@Override
	public boolean needCached() {
		return Global.MEMCACHE_DEFAULT;
	}

	@Override
	public String serialize() throws Exception {
		JSONObject jnode = new JSONObject();
		String key;
		Variant value;
		try {
			for (Entry<String, Variant> entry : map.entrySet()) {
				key = entry.getKey();
				value = entry.getValue();

				if (!value.isSerialize()) {
					continue;
				}
				//jnode.put(key, (value == null) ? JSONObject.NULL : value);
				jnode.put(key, value.getValue());

			}
			jnode.put("pk", this.getPk());
			jnode.put("entity", this.getEntity());
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return jnode.toString();
	}

	@Override
	public void deserialize(String str) throws Exception {
		this.resetValues();
		try {
			JSONObject jnode = new JSONObject(str);
			jnode.remove("pk");
			jnode.remove("entity");
			String key, value;
			for (Iterator<?> it = jnode.keys(); it.hasNext();) {
				key = it.next().toString();
				value = jnode.isNull(key) ? null : jnode.getString(key);
				this.set(key, value);
			}
		} catch (JSONException e) {
			e.printStackTrace();
		}
	}

	@Override
	public Set<String> keySet() {
		return map.keySet();
	}

	@Override
	public void setEntity(String entity) {
		this.entity = entity;
	}

	@Override
	public String getEntity() {
		return this.entity;
	}

	@Override
	public void set(String key, boolean value) {
		this.set(key, String.valueOf(value));
	}

	@Override
	public void set(String key, Date value) {
		if (value == null) {
			this.set(key, (String) null);
		} else {
			this.set(key, (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(value));
		}
	}

	@Override
	public void set(String key, double value) {
		this.set(key, String.valueOf(value));
	}

	@Override
	public void set(String key, float value) {
		this.set(key, String.valueOf(value));
	}

	@Override
	public void set(String key, int value) {
		this.set(key, String.valueOf(value));
	}

	@Override
	public void set(String key, long value) {
		this.set(key, String.valueOf(value));
	}

	@Override
	public void set(String key, String value) {
		if (map.containsKey(key)) {
			//map.get(key).type = value.getClass();
			if (value != null) {
				map.get(key).setValue(sFormat(value));
			} else {
				map.get(key).setValue(value);
			}
		} else {
			//throw
			log.error(this.getClass().toString() + " does not has key \"" + key + "\".");
		}
	}

	@Override
	public boolean getBoolean(String key) {
		boolean value = false;
		if (map.containsKey(key)) {
			String v = map.get(key).getValue();
			if (v != null && v.length() != 0) {
				value = Boolean.parseBoolean(v);
			}
		} else {
			// throw
		}
		return value;
	}

	@Override
	public Date getDate(String key) {
		Date value = null;
		if (map.containsKey(key)) {
			try {
				String v = map.get(key).getValue();
				if (v != null && v.length() != 0) {
					value = (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).parse(v);
				}
			} catch (ParseException e) {
				//e.printStackTrace();
			}
		}
		return value;
	}

	@Override
	public double getDouble(String key) {
		double value = 0;
		if (map.containsKey(key)) {
			String v = map.get(key).getValue();
			if (v != null && v.length() != 0) {
				value = Double.parseDouble(v);
			}
		} else {
			// throw
		}
		return value;
	}

	@Override
	public float getFloat(String key) {
		float value = 0;
		if (map.containsKey(key)) {
			String v = map.get(key).getValue();
			if (v != null && v.length() != 0) {
				value = Float.parseFloat(v);
			}
		}
		return value;
	}

	@Override
	public int getInt(String key) {
		int value = 0;
		if (map.containsKey(key)) {
			String v = map.get(key).getValue();
			if (v != null && v.length() != 0) {
				value = Integer.parseInt(v);
			}
		} else {
			// throw
		}
		return value;
	}

	@Override
	public long getLong(String key) {
		long value = 0;
		if (map.containsKey(key)) {
			String v = map.get(key).getValue();
			if (v != null && v.length() != 0) {
				value = Long.parseLong(v);
			}
		}
		return value;
	}

	@Override
	public String getString(String key) {
		String value = null;
		if (map.containsKey(key)) {
			value = map.get(key).getValue();
		} else {
			// throw
		}
		return value;
	}

	@Override
	public String getAliasName(String key) {
		String alias = null;
		if (map.containsKey(key)) {
			alias = map.get(key).getAlias();
		}
		return alias;
	}

	@Override
	public boolean isPk(String key) {
		boolean value = false;
		if (map.containsKey(key)) {
			value = map.get(key).isPk();
		} else {
			// throw
		}
		return value;
	}

	@Override
	public boolean isPersistent(String key) {
		boolean value = false;
		if (map.containsKey(key)) {
			value = map.get(key).isPersistent();
		} else {
			// throw
		}
		return value;
	}

	@Override
	public boolean isSerialize(String key) {
		boolean value = false;
		if (map.containsKey(key)) {
			value = map.get(key).isSerialize();
		} else {
			// throw
		}
		return value;
	}

	@Override
	public boolean isNullable(String key) {
		boolean value = false;
		if (map.containsKey(key)) {
			value = map.get(key).isNullable();
		} else {
			// throw
		}
		return value;
	}

	@Override
	public int getLength(String key) {
		int value = 0;
		if (map.containsKey(key)) {
			value = map.get(key).getLength();
		} else {
			// throw
		}
		return value;
	}

	@Override
	public VariantType getVariantType(String key) {
		VariantType value = VariantType.STRING;
		if (map.containsKey(key)) {
			value = map.get(key).getType();
		} else {
			// throw
		}
		return value;
	}

	@Override
	public String getPk() {
		String pk = "id";
		for (String key : map.keySet()) {
			if (map.get(key).isPk()) {
				String alias = map.get(key).getAlias();
				pk = (alias == null) ? key : alias;
				break;
			}
		}
		return pk;
	}

	@Override
	public String getPkValue() {
		String value = "";
		for (String key : map.keySet()) {
			if (map.get(key).isPk()) {
				value = map.get(key).getValue();
				break;
			}
		}
		return value;
	}

	@Override
	public void setPkValue(String value) {
		for (String key : map.keySet()) {
			if (map.get(key).isPk()) {
				map.get(key).setValue(value);
				break;
			}
		}
	}

	@Override
	public boolean isValid() {
		return !this.getPkValue().equals(SerializableObject.INVALID_ID); // id为-1的认为是一个无效的对象，只是和null进行区分
	}

	@Override
	public String toString() {
		return this.map.toString();
	}

	public static String sFormat(String sDate) {
		Pattern pattern = Pattern.compile("\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2}\\.\\d*");
		Matcher matcher = pattern.matcher(sDate);
		if (matcher.find()) {
			return sDate.replaceAll("\\.\\d{1,3}$", "");
		}
		return sDate;
	}

}
